package com.deep.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.deep.common.model.constant.ProductConstant;
import com.deep.common.model.dto.SkuFullReductionTO;
import com.deep.common.model.dto.SkuHasStockTO;
import com.deep.common.model.dto.SpuBoundTO;
import com.deep.common.model.dto.es.SkuEsModel;
import com.deep.common.utils.PageUtils;
import com.deep.common.utils.Query;
import com.deep.common.utils.R;
import com.deep.product.dao.AttrDao;
import com.deep.product.dao.SpuInfoDao;
import com.deep.product.dao.SpuInfoDescDao;
import com.deep.product.model.entity.*;
import com.deep.product.model.vo.*;
import com.deep.product.exception.FeignRequestException;
import com.deep.product.feign.CouponFeignService;
import com.deep.product.feign.SearchFeignService;
import com.deep.product.feign.WareFeignService;
import com.deep.product.service.*;
import org.apache.shiro.util.Assert;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {

    @Autowired
    private SpuInfoDao spuInfoDao;
    @Autowired
    private SpuInfoDescDao spuInfoDescDao;
    @Autowired
    private AttrDao attrDao;
    @Autowired
    private SearchFeignService searchFeignService;
    @Autowired
    private WareFeignService wareFeignService;
    @Autowired
    private BrandService brandService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private SkuInfoService skuInfoService;
    @Autowired
    private SkuImagesService skuImagesService;
    @Autowired
    private SkuSaleAttrValueService skuSaleAttrValueService;
    @Autowired
    private SpuImagesService spuImagesService;
    @Autowired
    private ProductAttrValueService productAttrValueService;
    @Autowired
    private CouponFeignService couponFeignService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                new QueryWrapper<SpuInfoEntity>()
        );

        return new PageUtils(page);
    }

    @Transactional
    @Override
    public void saveSpuInfo(SpuSaveVO spuSaveVO) {
        Assert.notNull(spuSaveVO, "supSaveVO 不能为空!");

        // 1、保存spu基本信息  pms_spu_info
        SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
        spuInfoEntity.setCreateTime(new Date());
        spuInfoEntity.setUpdateTime(new Date());
        BeanUtils.copyProperties(spuSaveVO, spuInfoEntity);
        spuInfoDao.insert(spuInfoEntity);
        Long spuId = spuInfoEntity.getId();       // MybatisPlus插入成功后会自动将id注入到实体类

        // 2、保存spu的描述图片 pms_spu_info_desc
        List<String> decrypt = spuSaveVO.getDecript();
        SpuInfoDescEntity spuInfoDescEntity = new SpuInfoDescEntity();
        spuInfoDescEntity.setSpuId(spuId);
        spuInfoDescEntity.setDecript(String.join(",", decrypt));    // String.join(",", decrypt)用逗号符号隔开
        spuInfoDescDao.insert(spuInfoDescEntity);

        // 3、保存spu的图片集  pms_sku_images
        List<String> images = spuSaveVO.getImages();
        spuImagesService.saveImages(spuId, images);

        // 4、保存spu的规格参数 pms_product_attr_value
        List<BaseAttrsVO> baseAttrsVOS = spuSaveVO.getBaseAttrs();
        List<ProductAttrValueEntity> productAttrValueEntities = baseAttrsVOS.stream().map(item -> {
            ProductAttrValueEntity valueEntity = new ProductAttrValueEntity();
            valueEntity.setAttrId(item.getAttrId());
            // 可能页面没用传入属性名字 根据属性id查到所有属性 给名字赋值
            AttrEntity attrEntity = attrDao.selectById(item.getAttrId());
            attrEntity.setAttrName(attrEntity.getAttrName());
            valueEntity.setAttrValue(item.getAttrValues());
            valueEntity.setQuickShow(item.getShowDesc());
            valueEntity.setSpuId(spuId);
            valueEntity.setAttrSort(0);
            return valueEntity;
        }).collect(Collectors.toList());

        productAttrValueService.saveBatch(productAttrValueEntities);

        // 5、保存spu的积分信息 gulimall_sms/sms_spu_bounds
        BoundsVO bounds = spuSaveVO.getBounds();
        SpuBoundTO spuBoundTO = new SpuBoundTO();
        BeanUtils.copyProperties(bounds, spuBoundTO);
        spuBoundTO.setSpuId(spuId);
        R feignResult = couponFeignService.saveSpuBounds(spuBoundTO);
        if (feignResult.getCode() != 0) {
            throw new RuntimeException("远程保存积分失败!");
        }

        // 6、保存对应的所有sku信息

        List<SkuVO> skuVOS = spuSaveVO.getSkus();
        if (skuVOS != null && skuVOS.size() > 0) {
            skuVOS.forEach((item) -> {

                // 6.1、保存sku的基本信息   pms_sku_info
                SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
                BeanUtils.copyProperties(item, skuInfoEntity);
                skuInfoEntity.setBrandId(spuInfoEntity.getBrandId());
                skuInfoEntity.setCatalogId(spuInfoEntity.getCatalogId());
                skuInfoEntity.setSpuId(spuId);
                skuInfoEntity.setSkuDefaultImg(getDefaultImg(item));
                skuInfoEntity.setSaleCount((long) (Math.random() * 2888));
                skuInfoService.save(skuInfoEntity);

                // 6.2、保存sku的图片信息   pms_sku_images
//                Long skuId = skuInfoEntity.getSkuId();
                Long skuId = Long.valueOf(skuInfoService.count());
                List<SkuImagesEntity> imagesEntities = item.getImages().stream().map(img -> {
                    SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
                    skuImagesEntity.setId(skuId);
                    skuImagesEntity.setImgUrl(img.getImgUrl());
                    skuImagesEntity.setDefaultImg(img.getDefaultImg());
                    return skuImagesEntity;
                }).filter(entity ->
                        StringUtils.hasLength(entity.getImgUrl())   // 返回true就会保存 返回false就会过滤
                ).collect(Collectors.toList());
                skuImagesService.saveBatch(imagesEntities);

                // 6.3、保存sku的销售属性   pms_sku_sale_attr_value
                List<AttrNameValueVO> attrs = item.getAttr();
                List<SkuSaleAttrValueEntity> skuSaleAttrValueEntities = attrs.stream().map((attr) -> {
                    SkuSaleAttrValueEntity skuSaleAttrValueEntity = new SkuSaleAttrValueEntity();
                    BeanUtils.copyProperties(attr, skuSaleAttrValueEntity);
                    skuSaleAttrValueEntity.setSkuId(skuId);
                    return skuSaleAttrValueEntity;
                }).collect(Collectors.toList());
                skuSaleAttrValueService.saveBatch(skuSaleAttrValueEntities);

                // 6.4、保存sku的优惠信息   gulimall_sms/sms_sku_ladder、sms_sku_full_reduction、sms_member_price
                SkuFullReductionTO skuFullReductionTO = new SkuFullReductionTO();
                BeanUtils.copyProperties(item, skuFullReductionTO);
                skuFullReductionTO.setSkuId(skuId);

                if (skuFullReductionTO.getFullCount() > 0
                        || (skuFullReductionTO.getFullPrice().compareTo(new BigDecimal("0")) > 0)) {
                    R r1 = couponFeignService.saveSkuReduction(skuFullReductionTO);
                    if (r1.getCode() != 0) {
                        log.error("远程保存sku优惠信息失败");
                    }
                }

            });
        }
    }

    /**
     * 获取默认图片
     *
     * @param skuVO sku网络传输对象
     * @return 默认图片的oss地址
     */
    private String getDefaultImg(SkuVO skuVO) {
        Assert.notNull(skuVO, "skuVO不能为空!");

        List<ImagesVO> images = skuVO.getImages();
        for (ImagesVO image : images) {
            if (image.getDefaultImg() == 1) {
                return image.getImgUrl();
            }
        }
        return "";
    }

    @Override
    public PageUtils queryDetail(Map<String, Object> params) {
        QueryWrapper<SpuInfoEntity> wrapper = new QueryWrapper<>();

        String key = (String) params.get("key");
        if (StringUtils.hasLength(key)) {
            wrapper.like("spu_name", key).or();
        }
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                wrapper
        );

        return new PageUtils(page);
    }

    /**
     * 不一样的属性：skuPrice、skuImg、hasStock、hotScore、
     * brandName、brandImg、catalogName、attrs
     */
    @Transactional
    @Override
    public void up(Long spuId) {
        // 1、组装数据
        // ①、查出当前spuId对应的所有sku信息、品牌名、品牌logo、分类名、基本属性信息
        List<SkuInfoEntity> skuInfoEntities =
                skuInfoService.list(new QueryWrapper<SkuInfoEntity>().eq("spu_id", spuId));

        // 查询spu品牌名、品牌logo、分类名
        SpuInfoEntity spuInfoEntity = this.getById(spuId);
        BrandEntity brand = brandService.getById(spuInfoEntity.getBrandId());
        String brandName = brand.getName();
        String brandLogo = brand.getLogo();
        String catalogName = categoryService.getById(spuInfoEntity.getCatalogId()).getName();

        // 查询spu基本属性信息并封装到SkuEsModel.Attrs
        List<ProductAttrValueEntity> baseAttrs = productAttrValueService.baseAttrListForSpu(spuId);
        List<SkuEsModel.Attrs> baseESAttrs = baseAttrs.stream().map(item -> {
            return new SkuEsModel.Attrs(item.getAttrId(), item.getAttrName(), item.getAttrValue());
        }).collect(Collectors.toList());

        // 获取skuId并封装到集合
        List<Long> skuIdList = skuInfoEntities.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());
        // 查询skuIdList中所有的skuId是否有库存
        Map<Long, Boolean> stockMap = hasStock(skuIdList);
        // ②、封装成上架商品检索模型集合
        List<SkuEsModel> skuEsModels = skuInfoEntities.stream().map(item -> {
            // 封装数据
            SkuEsModel skuEsModel = new SkuEsModel();
            BeanUtils.copyProperties(item, skuEsModel);
            skuEsModel.setSkuPrice(item.getPrice());
            skuEsModel.setSkuImg(item.getSkuDefaultImg());
            skuEsModel.setBrandName(brandName);
            skuEsModel.setBrandImg(brandLogo);
            skuEsModel.setCatalogName(catalogName);
            baseESAttrs.addAll(getSkuBaseAttrs(item.getSkuId()));
            skuEsModel.setAttrs(baseESAttrs);
            skuEsModel.setHasStock(stockMap.get(item.getSkuId()));
            // TODO 2、热度评分
            skuEsModel.setHotScore(100L);
            return skuEsModel;
        }).collect(Collectors.toList());

        // TODO 2、发送给es进行保存发给ES进行保存  mall-search
        R r = searchFeignService.productStatusUp(skuEsModels);
        if (r.getCode() == 0) {
            // 远程调用成功
            // 更改spu发布状态
            baseMapper.updateSpuStatus(spuId, ProductConstant.StatusEnum.SPU_UP.getCode());
        } else {
            // 远程调用失败 TODO 接口幂等性 重试机制
        }
    }

    @Override
    public SpuInfoEntity getSpuInfoBySkuId(Long skuId) {
        Assert.notNull(skuId, "skuId不能为空!");
        Long spuId = skuInfoService.getSpuIdBySkuId(skuId);
        return baseMapper.selectOne(new QueryWrapper<SpuInfoEntity>().eq("id", spuId));
    }

    /**
     * 远程调用库存系统，查询是否有库存
     *
     * @param skuIdList 包含skuId的集合
     * @return 是否包含库存的map映射
     */
    private Map<Long, Boolean> hasStock(List<Long> skuIdList) {
        Assert.notNull(skuIdList, "skuId不能为空!");

        List<SkuHasStockTO> skuHasStockTOS = wareFeignService.getSkusHasStock(skuIdList);

        if (skuHasStockTOS.size() <= 0) {
            throw new FeignRequestException("仓库存储远程服务调用失败!");
        }

        Map<Long, Boolean> stockMap = new HashMap<>();

        for (SkuHasStockTO skStockTO : skuHasStockTOS) {
            stockMap.put(skStockTO.getSkuId(), skStockTO.getHasStock());
        }

        return stockMap;
    }

    /**
     * 查询sku基础属性信息
     *
     * @param skuId skuId
     * @return 包含销售信息的可检索集合
     */
    private List<SkuEsModel.Attrs> getSkuBaseAttrs(Long skuId) {
        Assert.notNull(skuId, "skuId不能为空!");
        List<ProductAttrValueEntity> baseAttrValueEntities =
                productAttrValueService.list(new QueryWrapper<ProductAttrValueEntity>().eq("spu_id", skuId));
        return baseAttrValueEntities.stream()
                .map(item -> new SkuEsModel.Attrs(item.getId(), item.getAttrName(), item.getAttrValue()))
                .collect(Collectors.toList());
    }

}